#include "pe.h"
#include "file_cmd.h"
#include "int_util.h"
#include <memory.h>
#include <string.h>

/****************************************************************************\
 * Private Variables/Functions
\****************************************************************************/

static mdt_col_def s_default_cols[NUMBER_OF_METADATA_COLUMNS] =
{
	//                          name,                          type, ex_type, offset, sz
	// Module
	/*   0 */ { L"Generation",        MDCOLT_U2,                     MDCOLTEX__NONE, 0, 2 },
	/*   1 */ { L"Name",              MDCOLT_S_STRINGS,              MDCOLTEX__NONE, 0, 0 },
	/*   2 */ { L"Mvid",              MDCOLT_S_GUID,                 MDCOLTEX__NONE, 0, 0 },
	/*   3 */ { L"EncId",             MDCOLT_S_GUID,                 MDCOLTEX__NONE, 0, 0 },
	/*   4 */ { L"EncBaseId",         MDCOLT_S_GUID,                 MDCOLTEX__NONE, 0, 0 },
	// TypeRef
	/*   5 */ { L"ResolutionScope",   MDCOLT_CT_ResolutionScope,     MDCOLTEX__NONE, 0, 0 },
	/*   6 */ { L"Name",              MDCOLT_S_STRINGS,              MDCOLTEX__NONE, 0, 0 },
	/*   7 */ { L"Namespace",         MDCOLT_S_STRINGS,              MDCOLTEX__NONE, 0, 0 },
	// TypeDef
	/*   8 */ { L"Flags",             MDCOLT_U4,                     MDCOLTEX_TypeFlags, 0, 4 },
	/*   9 */ { L"Name",              MDCOLT_S_STRINGS,              MDCOLTEX__NONE, 0, 0 },
	/*  10 */ { L"Namespace",         MDCOLT_S_STRINGS,              MDCOLTEX__NONE, 0, 0 },
	/*  11 */ { L"Extends",           MDCOLT_CT_TypeDefOrRef,        MDCOLTEX__NONE, 0, 0 },
	/*  12 */ { L"FieldList",         MDCOLT_RID_Field,              MDCOLTEX__NONE, 0, 0 },
	/*  13 */ { L"MethodList",        MDCOLT_RID_Method,             MDCOLTEX__NONE, 0, 0 },
	// FieldPtr
	/*  14 */ { L"Field",             MDCOLT_RID_Field,              MDCOLTEX__NONE, 0, 0 },
	// Field
	/*  15 */ { L"Flags",             MDCOLT_U2,                     MDCOLTEX_FieldFlags, 0, 2 },
	/*  16 */ { L"Name",              MDCOLT_S_STRINGS,              MDCOLTEX__NONE, 0, 0 },
	/*  17 */ { L"Signature",         MDCOLT_S_BLOB,                 MDCOLTEX__NONE, 0, 0 },
	// MethodPtr
	/*  18 */ { L"Method",            MDCOLT_RID_Method,             MDCOLTEX__NONE, 0, 0 },
	// Method
	/*  19 */ { L"RVA",               MDCOLT_U4,                     MDCOLTEX_RVA, 0, 4 },
	/*  20 */ { L"ImplFlags",         MDCOLT_U2,                     MDCOLTEX_MethodImplFlags, 0, 2 },
	/*  21 */ { L"Flags",             MDCOLT_U2,                     MDCOLTEX_MethodFlags, 0, 2 },
	/*  22 */ { L"Name",              MDCOLT_S_STRINGS,              MDCOLTEX__NONE, 0, 0 },
	/*  23 */ { L"Signature",         MDCOLT_S_BLOB,                 MDCOLTEX__NONE, 0, 0 },
	/*  24 */ { L"ParamList",         MDCOLT_RID_Param,              MDCOLTEX__NONE, 0, 0 },
	// ParamPtr
	/*  25 */ { L"Param",             MDCOLT_RID_Param,              MDCOLTEX__NONE, 0, 0 },
	// Param
	/*  26 */ { L"Flags",             MDCOLT_U2,                     MDCOLTEX_ParamFlags, 0, 2 },
	/*  27 */ { L"Sequence",          MDCOLT_U2,                     MDCOLTEX__NONE, 0, 2 },
	/*  28 */ { L"Name",              MDCOLT_S_STRINGS,              MDCOLTEX__NONE, 0, 0 },
	// InterfaceImpl
	/*  29 */ { L"Class",             MDCOLT_RID_TypeDef,            MDCOLTEX__NONE, 0, 0 },
	/*  30 */ { L"Interface",         MDCOLT_CT_TypeDefOrRef,        MDCOLTEX__NONE, 0, 0 },
	// MemberRef
	/*  31 */ { L"Class",             MDCOLT_CT_MemberRefParent,     MDCOLTEX__NONE, 0, 0 },
	/*  32 */ { L"Name",              MDCOLT_S_STRINGS,              MDCOLTEX__NONE, 0, 0 },
	/*  33 */ { L"Signature",         MDCOLT_S_BLOB,                 MDCOLTEX__NONE, 0, 0 },
	// Constant
	/*  34 */ { L"Type",              MDCOLT_U1,                     MDCOLTEX_ElementType, 0, 1 },
	/*  35 */ { L"<Padding>",         MDCOLT_U1,                     MDCOLTEX__NONE, 0, 1 },
	/*  36 */ { L"Parent",            MDCOLT_CT_HasConstant,         MDCOLTEX__NONE, 0, 0 },
	/*  37 */ { L"Value",             MDCOLT_S_BLOB,                 MDCOLTEX__NONE, 0, 0 },
	// CustomAttribute
	/*  38 */ { L"Parent",            MDCOLT_CT_HasCustomAttribute,  MDCOLTEX__NONE, 0, 0 },
	/*  39 */ { L"Type",              MDCOLT_CT_CustomAttributeType, MDCOLTEX__NONE, 0, 0 },
	/*  40 */ { L"Value",             MDCOLT_S_BLOB,                 MDCOLTEX__NONE, 0, 0 },
	// FieldMarshal
	/*  41 */ { L"Parent",            MDCOLT_CT_HasFieldMarshal,     MDCOLTEX__NONE, 0, 0 },
	/*  42 */ { L"NativeType",        MDCOLT_S_BLOB,                 MDCOLTEX__NONE, 0, 0 },
	// DeclSecurity
	/*  43 */ { L"Action",            MDCOLT_U2,                     MDCOLTEX_SecurityAction, 0, 2 },
	/*  44 */ { L"Parent",            MDCOLT_CT_HasDeclSecurity,     MDCOLTEX__NONE, 0, 0 },
	/*  45 */ { L"PermissionSet",     MDCOLT_S_BLOB,                 MDCOLTEX__NONE, 0, 0 },
	// ClassLayout
	/*  46 */ { L"PackageSize",       MDCOLT_U2,                     MDCOLTEX__NONE, 0, 2 },
	/*  47 */ { L"ClassSize",         MDCOLT_U4,                     MDCOLTEX__NONE, 0, 4 },
	/*  48 */ { L"Parent",            MDCOLT_RID_TypeDef,            MDCOLTEX__NONE, 0, 0 },
	// FieldLayout
	/*  49 */ { L"Offset",            MDCOLT_U4,                     MDCOLTEX__NONE, 0, 4 },
	/*  50 */ { L"Field",             MDCOLT_RID_Field,              MDCOLTEX__NONE, 0, 0 },
	// StandAloneSig
	/*  51 */ { L"Signature",         MDCOLT_S_BLOB,                 MDCOLTEX__NONE, 0, 0 },
	// EventMap
	/*  52 */ { L"Parent",            MDCOLT_RID_TypeDef,            MDCOLTEX__NONE, 0, 0 },
	/*  53 */ { L"EventList",         MDCOLT_RID_Event,              MDCOLTEX__NONE, 0, 0 },
	// EventPtr
	/*  54 */ { L"Event",             MDCOLT_RID_Event,              MDCOLTEX__NONE, 0, 0 },
	// Event
	/*  55 */ { L"Flags",             MDCOLT_U2,                     MDCOLTEX_EventFlags, 0, 2 },
	/*  56 */ { L"Name",              MDCOLT_S_STRINGS,              MDCOLTEX__NONE, 0, 0 },
	/*  57 */ { L"Type",              MDCOLT_CT_TypeDefOrRef,        MDCOLTEX__NONE, 0, 0 },
	// PropertyMap
	/*  58 */ { L"Parent",            MDCOLT_RID_TypeDef,            MDCOLTEX__NONE, 0, 0 },
	/*  59 */ { L"PropertyList",      MDCOLT_RID_Property,           MDCOLTEX__NONE, 0, 0 },
	// PropertyPtr
	/*  60 */ { L"Property",          MDCOLT_RID_Property,           MDCOLTEX__NONE, 0, 0 },
	// Property
	/*  61 */ { L"Flags",             MDCOLT_U2,                     MDCOLTEX_PropertyFlags, 0, 2 },
	/*  62 */ { L"Name",              MDCOLT_S_STRINGS,              MDCOLTEX__NONE, 0, 0 },
	/*  63 */ { L"Type",              MDCOLT_S_BLOB,                 MDCOLTEX__NONE, 0, 0 },
	// MethodSemantics
	/*  64 */ { L"Semantic",          MDCOLT_U2,                     MDCOLTEX_MethodSemanticsFlags, 0, 2 },
	/*  65 */ { L"Method",            MDCOLT_RID_Method,             MDCOLTEX__NONE, 0, 0 },
	/*  66 */ { L"Association",       MDCOLT_CT_HasSemantics,        MDCOLTEX__NONE, 0, 0 },
	// MethodImpl
	/*  67 */ { L"Class",             MDCOLT_RID_TypeDef,            MDCOLTEX__NONE, 0, 0 },
	/*  68 */ { L"MethodBody",        MDCOLT_CT_MethodDefOrRef,      MDCOLTEX__NONE, 0, 0 },
	/*  69 */ { L"MethodDeclaration", MDCOLT_CT_MethodDefOrRef,      MDCOLTEX__NONE, 0, 0 },
	// ModuleRef
	/*  70 */ { L"Name",              MDCOLT_S_STRINGS,              MDCOLTEX__NONE, 0, 0 },
	// TypeSpec
	/*  71 */ { L"Signature",         MDCOLT_S_BLOB,                 MDCOLTEX__NONE, 0, 0 },
	// ImplMap
	/*  72 */ { L"MappingFlags",      MDCOLT_U2,                     MDCOLTEX_PInvokeMapFlags, 0, 2 },
	/*  73 */ { L"MemberForwarded",   MDCOLT_CT_MemberForwarded,     MDCOLTEX__NONE, 0, 0 },
	/*  74 */ { L"ImportName",        MDCOLT_S_STRINGS,              MDCOLTEX__NONE, 0, 0 },
	/*  75 */ { L"ImportScope",       MDCOLT_RID_ModuleRef,          MDCOLTEX__NONE, 0, 0 },
	// FieldRVA
	/*  76 */ { L"RVA",               MDCOLT_U4,                     MDCOLTEX_RVA, 0, 4 },
	/*  77 */ { L"Field",             MDCOLT_RID_Field,              MDCOLTEX__NONE, 0, 0 },
	// ENCLog
	/*  78 */ { L"Token",             MDCOLT_U4,                     MDCOLTEX__NONE, 0, 4 },
	/*  79 */ { L"FuncCode",          MDCOLT_U4,                     MDCOLTEX__NONE, 0, 4 },
	// ENCMap
	/*  80 */ { L"Token",             MDCOLT_U4,                     MDCOLTEX__NONE, 0, 4 },
	// Assembly
	/*  81 */ { L"HashAlgId",         MDCOLT_U4,                     MDCOLTEX_HashAlg, 0, 4 },
	/*  82 */ { L"MajorVersion",      MDCOLT_U2,                     MDCOLTEX__NONE, 0, 2 },
	/*  83 */ { L"MinorVersion",      MDCOLT_U2,                     MDCOLTEX__NONE, 0, 2 },
	/*  84 */ { L"BuildNumer",        MDCOLT_U2,                     MDCOLTEX__NONE, 0, 2 },
	/*  85 */ { L"RevisionNumber",    MDCOLT_U2,                     MDCOLTEX__NONE, 0, 2 },
	/*  86 */ { L"Flags",             MDCOLT_U4,                     MDCOLTEX_AssemblyFlags, 0, 4 },
	/*  87 */ { L"PublicKey",         MDCOLT_S_BLOB,                 MDCOLTEX__NONE, 0, 0 },
	/*  88 */ { L"Name",              MDCOLT_S_STRINGS,              MDCOLTEX__NONE, 0, 0 },
	/*  89 */ { L"Locale",            MDCOLT_S_STRINGS,              MDCOLTEX__NONE, 0, 0 },
	// AssemblyProcessor
	/*  90 */ { L"Processor",         MDCOLT_U4,                     MDCOLTEX__NONE, 0, 4 },
	// AssemblyOS
	/*  91 */ { L"OSPlatformId",      MDCOLT_U4,                     MDCOLTEX__NONE, 0, 4 },
	/*  92 */ { L"OSMajorVersion",    MDCOLT_U4,                     MDCOLTEX__NONE, 0, 4 },
	/*  93 */ { L"OSMinorVersion",    MDCOLT_U4,                     MDCOLTEX__NONE, 0, 4 },
	// AssemblyRef
	/*  94 */ { L"MajorVersion",      MDCOLT_U2,                     MDCOLTEX__NONE, 0, 2 },
	/*  95 */ { L"MinorVersion",      MDCOLT_U2,                     MDCOLTEX__NONE, 0, 2 },
	/*  96 */ { L"BuildNumer",        MDCOLT_U2,                     MDCOLTEX__NONE, 0, 2 },
	/*  97 */ { L"RevisionNumber",    MDCOLT_U2,                     MDCOLTEX__NONE, 0, 2 },
	/*  98 */ { L"Flags",             MDCOLT_U4,                     MDCOLTEX_AssemblyFlags, 0, 4 },
	/*  99 */ { L"PublickKeyOrToken", MDCOLT_S_BLOB,                 MDCOLTEX__NONE, 0, 0 },
	/* 100 */ { L"Name",              MDCOLT_S_STRINGS,              MDCOLTEX__NONE, 0, 0 },
	/* 101 */ { L"Locale",            MDCOLT_S_STRINGS,              MDCOLTEX__NONE, 0, 0 },
	/* 102 */ { L"HashValue",         MDCOLT_S_BLOB,                 MDCOLTEX__NONE, 0, 0 },
	// AssemblyRefProcessor
	/* 103 */ { L"Processor",         MDCOLT_U4,                     MDCOLTEX__NONE, 0, 4 },
	/* 104 */ { L"AssemblyRef",       MDCOLT_RID_AssemblyRef,        MDCOLTEX__NONE, 0, 0 },
	// AssemblyRefOS
	/* 105 */ { L"OSPlatformId",      MDCOLT_U4,                     MDCOLTEX__NONE, 0, 4 },
	/* 106 */ { L"OSMajorVersion",    MDCOLT_U4,                     MDCOLTEX__NONE, 0, 4 },
	/* 107 */ { L"OSMinorVersion",    MDCOLT_U4,                     MDCOLTEX__NONE, 0, 4 },
	/* 108 */ { L"AssemblyRef",       MDCOLT_RID_AssemblyRef,        MDCOLTEX__NONE, 0, 0 },
	// File
	/* 109 */ { L"Flags",             MDCOLT_U4,                     MDCOLTEX_FileFlags, 0, 4 },
	/* 110 */ { L"Name",              MDCOLT_S_STRINGS,              MDCOLTEX__NONE, 0, 0 },
	/* 111 */ { L"HashValue",         MDCOLT_S_BLOB,                 MDCOLTEX__NONE, 0, 0 },
	// ExportedType
	/* 112 */ { L"Flags",             MDCOLT_U4,                     MDCOLTEX_TypeFlags, 0, 4 },
	/* 113 */ { L"TypeDefId",         MDCOLT_U4,                     MDCOLTEX__NONE, 0, 4 },
	/* 114 */ { L"TypeName",          MDCOLT_S_STRINGS,              MDCOLTEX__NONE, 0, 0 },
	/* 115 */ { L"TypeNamespace",     MDCOLT_S_STRINGS,              MDCOLTEX__NONE, 0, 0 },
	/* 116 */ { L"Implementation",    MDCOLT_CT_Implementation,      MDCOLTEX__NONE, 0, 0 },
	// ManifestResource
	/* 117 */ { L"Offset",            MDCOLT_U4,                     MDCOLTEX__NONE, 0, 4 },
	/* 118 */ { L"Flags",             MDCOLT_U4,                     MDCOLTEX_ManifestResourceFlags, 0, 4 },
	/* 119 */ { L"Name",              MDCOLT_S_STRINGS,              MDCOLTEX__NONE, 0, 0 },
	/* 120 */ { L"Implementation",    MDCOLT_CT_Implementation,      MDCOLTEX__NONE, 0, 0 },
	// NestedClass
	/* 121 */ { L"NestedClass",       MDCOLT_RID_TypeDef,            MDCOLTEX__NONE, 0, 0 },
	/* 122 */ { L"EnclosingClass",    MDCOLT_RID_TypeDef,            MDCOLTEX__NONE, 0, 0 },
	// GenericParam
	/* 123 */ { L"Number",            MDCOLT_U2,                     MDCOLTEX__NONE, 0, 2 },
	/* 124 */ { L"Flags",             MDCOLT_U2,                     MDCOLTEX_GenericParamFlags, 0, 2 },
	/* 125 */ { L"Owner",             MDCOLT_CT_TypeOrMethodDef,     MDCOLTEX__NONE, 0, 0 },
	/* 126 */ { L"Name",              MDCOLT_S_STRINGS,              MDCOLTEX__NONE, 0, 0 },
	// MethodSpec
	/* 127 */ { L"Method",            MDCOLT_CT_MethodDefOrRef,      MDCOLTEX__NONE, 0, 0 },
	/* 128 */ { L"Instantiation",     MDCOLT_S_BLOB,                 MDCOLTEX__NONE, 0, 0 },
	// GenericParamConstraint
	/* 129 */ { L"Owner",             MDCOLT_RID_GenericParam,       MDCOLTEX__NONE, 0, 0 },
	/* 130 */ { L"Constraint",        MDCOLT_CT_TypeDefOrRef,        MDCOLTEX__NONE, 0, 0 },
};

static mdt_tbl_def s_default_tbls[NUMBER_OF_METADATA_TABLES] =
{
	//                     name, cols, rec_size, rec_num, col_num, valid, sorted, rid_sz, p_data
	{ L"Module",                    0,        0,       0,       5,     0,      0,      2, NULL },
	{ L"TypeRef",                   5,        0,       0,       3,     0,      0,      2, NULL },
	{ L"TypeDef",                   8,        0,       0,       6,     0,      0,      2, NULL },
	{ L"FieldPtr",                 14,        0,       0,       1,     0,      0,      2, NULL },
	{ L"Field",                    15,        0,       0,       3,     0,      0,      2, NULL },
	{ L"MethodPtr",                18,        0,       0,       1,     0,      0,      2, NULL },
	{ L"Method",                   19,        0,       0,       6,     0,      0,      2, NULL },
	{ L"ParamPtr",                 25,        0,       0,       1,     0,      0,      2, NULL },
	{ L"Param",                    26,        0,       0,       3,     0,      0,      2, NULL },
	{ L"InterfaceImpl",            29,        0,       0,       2,     0,      0,      2, NULL },
	{ L"MemberRef",                31,        0,       0,       3,     0,      0,      2, NULL },
	{ L"Constant",                 34,        0,       0,       4,     0,      0,      2, NULL },
	{ L"CustomAttribute",          38,        0,       0,       3,     0,      0,      2, NULL },
	{ L"FieldMarshal",             41,        0,       0,       2,     0,      0,      2, NULL },
	{ L"DeclSecurity",             43,        0,       0,       3,     0,      0,      2, NULL },
	{ L"ClassLayout",              46,        0,       0,       3,     0,      0,      2, NULL },
	{ L"FieldLayout",              49,        0,       0,       2,     0,      0,      2, NULL },
	{ L"StandAloneSig",            51,        0,       0,       1,     0,      0,      2, NULL },
	{ L"EventMap",                 52,        0,       0,       2,     0,      0,      2, NULL },
	{ L"EventPtr",                 54,        0,       0,       1,     0,      0,      2, NULL },
	{ L"Event",                    55,        0,       0,       3,     0,      0,      2, NULL },
	{ L"PropertyMap",              58,        0,       0,       2,     0,      0,      2, NULL },
	{ L"PropertyPtr",              60,        0,       0,       1,     0,      0,      2, NULL },
	{ L"Property",                 61,        0,       0,       3,     0,      0,      2, NULL },
	{ L"MethodSemantics",          64,        0,       0,       3,     0,      0,      2, NULL },
	{ L"MethodImpl",               67,        0,       0,       3,     0,      0,      2, NULL },
	{ L"ModuleRef",                70,        0,       0,       1,     0,      0,      2, NULL },
	{ L"TypeSpec",                 71,        0,       0,       1,     0,      0,      2, NULL },
	{ L"ImplMap",                  72,        0,       0,       4,     0,      0,      2, NULL },
	{ L"FieldRVA",                 76,        0,       0,       2,     0,      0,      2, NULL },
	{ L"ENCLog",                   78,        0,       0,       2,     0,      0,      2, NULL },
	{ L"ENCMap",                   80,        0,       0,       1,     0,      0,      2, NULL },
	{ L"Assembly",                 81,        0,       0,       9,     0,      0,      2, NULL },
	{ L"AssemblyProcessor",        90,        0,       0,       1,     0,      0,      2, NULL },
	{ L"AssemblyOS",               91,        0,       0,       3,     0,      0,      2, NULL },
	{ L"AssemblyRef",              94,        0,       0,       9,     0,      0,      2, NULL },
	{ L"AssemblyRefProcessor",    103,        0,       0,       2,     0,      0,      2, NULL },
	{ L"AssemblyRefOS",           105,        0,       0,       4,     0,      0,      2, NULL },
	{ L"File",                    109,        0,       0,       3,     0,      0,      2, NULL },
	{ L"ExportedType",            112,        0,       0,       5,     0,      0,      2, NULL },
	{ L"ManifestResource",        117,        0,       0,       4,     0,      0,      2, NULL },
	{ L"NestedClass",             121,        0,       0,       2,     0,      0,      2, NULL },
	{ L"GenericParam",            123,        0,       0,       4,     0,      0,      2, NULL },
	{ L"MethodSpec",              127,        0,       0,       2,     0,      0,      2, NULL },
	{ L"GenericParamConstraint",  129,        0,       0,       2,     0,      0,      2, NULL },
};

static str_wc s_unused_table_name = L"<UNUSED>";

static coded_token_def s_default_coded_token[MDCOLT_CT__COUNT] =
{
	//                  name, tag_sz, tag_mask, tbl_num, col_sz, rec_lim, tbls
	{ L"TypeDefOrRef",             2,     0x03,      3,      2,  0x3FFF,    0 },
	{ L"HasConstant",              2,     0x03,      3,      2,  0x3FFF,    3 },
	{ L"HasCustomAttribute",       5,     0x1F,     22,      2,  0x07FF,    6 },
	{ L"HasFieldMarshal",          1,     0x01,      2,      2,  0x7FFF,   28 },
	{ L"HasDeclSecurity",          2,     0x03,      3,      2,  0x3FFF,   30 },
	{ L"MemberRefParent",          3,     0x07,      5,      2,  0x1FFF,   33 },
	{ L"HasSemantics",             1,     0x01,      2,      2,  0x7FFF,   38 },
	{ L"MethodDefOrRef",           1,     0x01,      2,      2,  0x7FFF,   40 },
	{ L"MemberForwarded",          1,     0x01,      2,      2,  0x7FFF,   42 },
	{ L"Implementation",           2,     0x03,      3,      2,  0x3FFF,   44 },
	{ L"CustomAttributeType",      3,     0x07,      5,      2,  0x1FFF,   47 },
	{ L"ResolutionScope",          2,     0x03,      4,      2,  0x3FFF,   52 },
	{ L"TypeOrMethodDef",          1,     0x01,      2,      2,  0x7FFF,   56 },
};

static coded_token_ref_tbl_def s_default_ct_ref_tbl[NUMBER_OF_CODED_TOKEN_REF_TBL] =
{
	// TypeDefOrRef
	/*  0 */ {  0, TBLID_TypeDef                },
	/*  1 */ {  1, TBLID_TypeRef                },
	/*  2 */ {  2, TBLID_TypeSpec               },
	// HasConstant
	/*  3 */ {  0, TBLID_Field                  },
	/*  4 */ {  1, TBLID_Param                  },
	/*  5 */ {  2, TBLID_Property               },
	// HasCustomAttribute
	/*  6 */ {  0, TBLID_Method                 },
	/*  7 */ {  1, TBLID_Field                  },
	/*  8 */ {  2, TBLID_TypeRef                },
	/*  9 */ {  3, TBLID_TypeDef                },
	/* 10 */ {  4, TBLID_Param                  },
	/* 11 */ {  5, TBLID_InterfaceImpl          },
	/* 12 */ {  6, TBLID_MemberRef              },
	/* 13 */ {  7, TBLID_Module                 },
	/* 14 */ {  8, TBLID_DeclSecurity           },
	/* 15 */ {  9, TBLID_Property               },
	/* 16 */ { 10, TBLID_Event                  },
	/* 17 */ { 11, TBLID_StandAloneSig          },
	/* 18 */ { 12, TBLID_ModuleRef              },
	/* 19 */ { 13, TBLID_TypeSpec               },
	/* 20 */ { 14, TBLID_Assembly               },
	/* 21 */ { 15, TBLID_AssemblyRef            },
	/* 22 */ { 16, TBLID_File                   },
	/* 23 */ { 17, TBLID_ExportedType           },
	/* 24 */ { 18, TBLID_ManifestResource       },
	/* 25 */ { 19, TBLID_GenericParam           },
	/* 26 */ { 20, TBLID_GenericParamConstraint },
	/* 27 */ { 21, TBLID_MethodSpec             },
	// HasFieldMarshal
	/* 28 */ {  0, TBLID_Field                  },
	/* 29 */ {  1, TBLID_Param                  },
	// HasDeclSecurity
	/* 30 */ {  0, TBLID_TypeDef                },
	/* 31 */ {  1, TBLID_Method                 },
	/* 32 */ {  2, TBLID_Assembly               },
	// MemberRefParent
	/* 33 */ {  0, TBLID_TypeDef                },
	/* 34 */ {  1, TBLID_TypeRef                },
	/* 35 */ {  2, TBLID_ModuleRef              },
	/* 36 */ {  3, TBLID_Method                 },
	/* 37 */ {  4, TBLID_TypeSpec               },
	// HasSemantics
	/* 38 */ {  0, TBLID_Event                  },
	/* 39 */ {  1, TBLID_Property               },
	// MethodDefOrRef
	/* 40 */ {  0, TBLID_Method                 },
	/* 41 */ {  1, TBLID_MemberRef              },
	// MemberForwarded
	/* 42 */ {  0, TBLID_Field                  },
	/* 43 */ {  1, TBLID_Method                 },
	// Implementation
	/* 44 */ {  0, TBLID_File                   },
	/* 45 */ {  1, TBLID_AssemblyRef            },
	/* 46 */ {  2, TBLID_ExportedType           },
	// CustomAttributeType
	/* 47 */ {  0, TBLID__UNUSED                },
	/* 48 */ {  1, TBLID__UNUSED                },
	/* 49 */ {  2, TBLID_Method                 },
	/* 50 */ {  3, TBLID_MemberRef              },
	/* 51 */ {  4, TBLID__UNUSED                },
	// ResolutionScope
	/* 52 */ {  0, TBLID_Module                 },
	/* 53 */ {  1, TBLID_ModuleRef              },
	/* 54 */ {  2, TBLID_AssemblyRef            },
	/* 55 */ {  3, TBLID_TypeRef                },
	// TypeOrMethodDef
	/* 56 */ {  0, TBLID_TypeDef                },
	/* 57 */ {  1, TBLID_Method                 },
};

static BOOL s_set_cli_hdr(pe_file *p_pe)
{
	image_data_directory dd_cli;
	size_t cli_offset;

	dd_cli = p_pe->p_data_dir[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR];

	memset(&p_pe->metadata, 0, sizeof(p_pe->metadata));

	if(!dd_cli.VirtualAddress)
		return TRUE;

	cli_offset = rva_to_offset(p_pe, dd_cli.VirtualAddress);

	if(cli_offset >= p_pe->length || cli_offset + sizeof(image_cor20_header) > p_pe->length)
	{
		wprintf(L"CLI header goes beyond the end of file.\n");
		return FALSE;
	}

	p_pe->metadata.p_cli_hdr = (image_cor20_header *)(p_pe->p_base + cli_offset);

	return TRUE;
}

static BOOL s_set_storage(pe_file *p_pe)
{
	char *p_char;

	p_pe->metadata.p_st_sig = (metadata_storage_signature *)(p_pe->p_base
		+ rva_to_offset(p_pe, p_pe->metadata.p_cli_hdr->MetaData.VirtualAddress));

	p_char = p_pe->metadata.p_st_sig->VersionString;
	while(*p_char) ++p_char;
	p_pe->metadata.p_st_hdr = (metadata_storage_header *)round_to((byte *)p_char + 1, 4);

	return TRUE;
}

static BOOL s_set_streams(pe_file *p_pe)
{
	size_t p_metadata_base;
	metadata_stream_header *p_sh;
	int n_sh;

	p_pe->metadata.p_stream_hdr = (metadata_stream_header *)
		((byte *)p_pe->metadata.p_st_hdr + sizeof(metadata_storage_header));

	p_metadata_base = rva_to_offset(p_pe,
		p_pe->metadata.p_cli_hdr->MetaData.VirtualAddress);

	for(n_sh = p_pe->metadata.p_st_hdr->NumberOfStreams,
		p_sh = p_pe->metadata.p_stream_hdr;
		n_sh > 0;
		--n_sh,
		p_sh = next_stream_header(p_sh))
	{
		if(strcmp(p_sh->Name, "#~") == 0)
		{
			p_pe->metadata.table_offset = p_metadata_base + p_sh->Offset;
			p_pe->metadata.table_length = p_sh->Size;
		}
		else if(strcmp(p_sh->Name, "#Strings") == 0)
		{
			p_pe->metadata.strings_offset = p_metadata_base + p_sh->Offset;
			p_pe->metadata.strings_length = p_sh->Size;
		}
		else if(strcmp(p_sh->Name, "#US") == 0)
		{
			p_pe->metadata.us_offset = p_metadata_base + p_sh->Offset;
			p_pe->metadata.us_length = p_sh->Size;
		}
		else if(strcmp(p_sh->Name, "#GUID") == 0)
		{
			p_pe->metadata.guid_offset = p_metadata_base + p_sh->Offset;
			p_pe->metadata.guid_length = p_sh->Size;
		}
		else if(strcmp(p_sh->Name, "#Blob") == 0)
		{
			p_pe->metadata.blob_offset = p_metadata_base + p_sh->Offset;
			p_pe->metadata.blob_length = p_sh->Size;
		}
	}

	return TRUE;
}

static BOOL s_set_tbl_hdr(pe_file *p_pe)
{
	if(p_pe->metadata.table_offset == 0)
	// Suppose the metadata structure is set to 0,
	// so int this case, p_table_hdr will be NULL.
		return TRUE;

	p_pe->metadata.p_table_hdr = (metadata_table_header *)
		(p_pe->p_base + p_pe->metadata.table_offset);

	p_pe->metadata.p_table_data
		= (byte *)p_pe->metadata.p_table_hdr
		+ sizeof(metadata_table_header)
		+ sizeof(u4) * num_of_1_u8(p_pe->metadata.p_table_hdr->MaskValid);

	return TRUE;
}

static BOOL s_set_tbl_data(pe_file *p_pe)
{
	u4 i, j;
	u8 tbl_mask;
	u1 stream_mask;
	metadata_table_header *p_th = p_pe->metadata.p_table_hdr;
	u4 *p_row = p_pe->metadata.p_table_hdr->TableRows;
	mdt_tbl_def *p_tbl_defs = p_pe->metadata.tbl_defs;
	mdt_col_def *p_col_defs = p_pe->metadata.col_defs;
	coded_token_def *p_ct_defs = p_pe->metadata.coded_tokens;
	coded_token_ref_tbl_def *p_ctrt_defs = p_pe->metadata.coded_token_ref_tbls;
	byte *p_tbl_data = p_pe->metadata.p_table_data;

	// Init tables, columns, coded token and its referenced tables definitions.
	memcpy(p_tbl_defs, s_default_tbls, sizeof(s_default_tbls));
	memcpy(p_col_defs, s_default_cols, sizeof(s_default_cols));
	memcpy(p_ct_defs, s_default_coded_token, sizeof(s_default_coded_token));
	memcpy(p_ctrt_defs, s_default_ct_ref_tbl, sizeof(s_default_ct_ref_tbl));
	memset(p_pe->metadata.stream_type_size, 0, sizeof(p_pe->metadata.stream_type_size));

	// Fill stream type sizes.
	for(i = 0, stream_mask = 1; i < MDCOLT_S__COUNT; ++i, stream_mask <<= 1)
		p_pe->metadata.stream_type_size[i] = (p_th->Heaps & stream_mask) ? 4 : 2;

	// Fill table rows and RID type sizes.
	for(i = 0, tbl_mask = 1;
		i < NUMBER_OF_METADATA_TABLES;
		++i, tbl_mask <<= 1)
	{
		if(p_th->MaskValid & tbl_mask)
		{
			p_tbl_defs[i].is_valid = 1;
			p_tbl_defs[i].record_num = *p_row;
			p_tbl_defs[i].rid_size = *p_row > 0xFFFF ? 4 : 2;
			++p_row;
		}

		p_tbl_defs[i].is_sorted = (p_th->MaskSorted & tbl_mask) ? 1 : 0;
	}

	// Fill coded token sizes.
	for(i = 0; i < MDCOLT_CT__COUNT; ++i)
	{
		u4 j;
		for(j = 0; j < s_default_coded_token[i].tbl_num; ++j)
		{
			u4 tid = s_default_ct_ref_tbl[s_default_coded_token[i].tables + j].table_id;
			if(tid < NUMBER_OF_METADATA_TABLES
				&& p_tbl_defs[tid].record_num > s_default_coded_token[i].record_limit)
			{
				p_ct_defs[i].col_size = 4;
				break;
			}
		}
	}

	// Fill column definitions.
	for(i = 0; i < NUMBER_OF_METADATA_COLUMNS; ++i)
	{
		u1 col_type = p_col_defs[i].type;
		if(/*col_type >= MDCOLT_RID__MIN &&*/ col_type <= MDCOLT_RID__MAX)
			p_col_defs[i].size = p_tbl_defs[col_type /*- MDCOLT_RID__MIN*/].rid_size;
		else if(col_type >= MDCOLT_CT__MIN && col_type <= MDCOLT_CT__MAX)
			p_col_defs[i].size = p_ct_defs[col_type - MDCOLT_CT__MIN].col_size;
		else if(col_type >= MDCOLT_S__MIN && col_type <= MDCOLT_S__MAX)
			p_col_defs[i].size = p_pe->metadata.stream_type_size[col_type - MDCOLT_S__MIN];
	}

	// Adjust table and column definitions
	for(i = 0; i < NUMBER_OF_METADATA_TABLES; ++i)
	{
		p_tbl_defs[i].p_data = p_tbl_data;

		for(j = 0; j < p_tbl_defs[i].col_num; ++j)
		{
			p_col_defs[p_tbl_defs[i].cols + j].offset = p_tbl_defs[i].record_size;
			p_tbl_defs[i].record_size += p_col_defs[p_tbl_defs[i].cols + j].size;
		}

		p_tbl_data += p_tbl_defs[i].record_num * p_tbl_defs[i].record_size;
	}

	return TRUE;
}

/****************************************************************************\
 * Public Functions
\****************************************************************************/

BOOL set_metadata(pe_file *p_pe)
{
	if(!CONTAINS_METADATA(p_pe))
		return TRUE;

	if(!s_set_cli_hdr(p_pe))
		return FALSE;

	if(!s_set_storage(p_pe))
		return FALSE;

	if(!s_set_streams(p_pe))
		return FALSE;

	if(!s_set_tbl_hdr(p_pe))
		return FALSE;

	if(!s_set_tbl_data(p_pe))
		return FALSE;

	return TRUE;
}

BOOL check_metadata(pe_file *p_pe)
{
	if(!CONTAINS_METADATA(p_pe))
	{
		wprintf(L"No metadata (not a managed image).\n");
		return FALSE;
	}

	return TRUE;
}

metadata_stream_header *next_stream_header(metadata_stream_header *p)
{
	byte *pb = (byte *)p->Name;
	while(*pb) ++pb;
	++pb;
	pb = round_to(pb, 4);

	return (metadata_stream_header *)pb;
}

str_wc get_metadata_table_name(u2 tid)
{
	if(tid < NUMBER_OF_METADATA_TABLES)
		return s_default_tbls[tid].name;
	else
		return s_unused_table_name;
};

byte *get_metadata_table_row_data(pe_file *p_pe, table_id tid, size_t rid)
{
	mdt_tbl_def *p_tbl = p_pe->metadata.tbl_defs + tid;
	return p_tbl->p_data + (rid - 1) * p_tbl->record_size;
}

BOOL format_metadata_token(pe_file *p_pe, u4 token, str_w str_buf, size_t str_len)
{
	size_t tid = METADATA_TOKEN_TID(token);
	size_t rid = METADATA_TOKEN_RID(token);

	if(!token)
	{
		swprintf(str_buf, str_len, L"<EMPTY>");
		return TRUE;
	}

	switch (token & MDT__MASK)
	{
	case MDT_Module                :
	case MDT_TypeRef               :
	case MDT_TypeDef               :
	case MDT_Field                 :
	case MDT_Method                :
	case MDT_Param                 :
	case MDT_InterfaceImpl         :
	case MDT_MemberRef             :
	case MDT_CustomAttribute       :
	case MDT_DeclSecurity          :
	case MDT_StandAloneSig         :
	case MDT_Event                 :
	case MDT_Property              :
	case MDT_ModuleRef             :
	case MDT_TypeSpec              :
	case MDT_Assembly              :
	case MDT_AssemblyRef           :
	case MDT_File                  :
	case MDT_ExportedType          :
	case MDT_ManifestResource      :
	case MDT_GenericParam          :
	case MDT_MethodSpec            :
	case MDT_GenericParamConstraint:
		if(rid > 0 && rid <= p_pe->metadata.tbl_defs[tid].record_num)
		{
			swprintf(str_buf, str_len, L"%s[%Xh (%d)]",
				p_pe->metadata.tbl_defs[tid].name, rid, rid);
			return TRUE;
		}
		else
		{
			swprintf(str_buf, str_len, L"<Invalid row number (FFFFFFh, 16777215)>", rid, rid);
			return FALSE;
		}
	case MDT_String                :
		if(rid > 0 && rid < p_pe->metadata.us_length)
		{
			swprintf(str_buf, str_len, L"#US[%Xh (%d)]", rid, rid);
			return TRUE;
		}
		else
		{
			swprintf(str_buf, str_len, L"<Invalid stream offset (FFFFFFh, 16777215)>", rid, rid);
			return FALSE;
		}
	default:
		swprintf(str_buf, str_len, L"<Invalid token type (%02Xh, %d)>", tid, tid);
		return FALSE;
	}
}

void format_metadata_token_direct(u4 token, str_w str_buf, size_t str_len)
{
	size_t tid = METADATA_TOKEN_TID(token);
	size_t rid = METADATA_TOKEN_RID(token);

	if(tid == 0x70)
		swprintf(str_buf, str_len, L"#US[%Xh (%d)]", rid, rid);
	else
		swprintf(str_buf, str_len, L"%s[%Xh (%d)]", s_default_tbls[tid].name, rid, rid);
}
